﻿using DotNetty.Codecs.Http.WebSockets;
using DotNetty.Transport.Channels;
using Newtonsoft.Json;
using NLog;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static WebSocket.Server.EventDelegate;

namespace WebSocket.Server
{
    public class ClientsManage
    {
        readonly WebSocketClientHandshaker handshaker;
        readonly DotNetty.Common.Concurrency.TaskCompletionSource completionSource;
        private readonly Logger _logger = LogManager.GetCurrentClassLogger();

        protected readonly Queue<FxpCommandAsyncEvent> CommandAsyncEvents = new Queue<FxpCommandAsyncEvent>();
        public IChannelHandlerContext ChannelHandlerContext { get; set; }
        public LinkedList<ContextParas> listContext  = new LinkedList<ContextParas>();

        public EventDelegate.EventRecv eventEventRecv;
        public EventDelegate.MsgSend eventMsgSend;
        public EventDelegate.MsgRecv eventMsgRecv;
        public EventDelegate.Accepted eventAccepted;
        public EventDelegate.Closed eventClosed;
        public EventDelegate.Info eventInfo;

        public ClientsManage()
        {
            eventMsgSend += new EventDelegate.MsgSend(OnMsgSend);
            eventMsgRecv += new EventDelegate.MsgRecv(OnMsgRecv);
            eventEventRecv += new EventDelegate.EventRecv(OnEventRecv);
            eventAccepted += new EventDelegate.Accepted(OnClientAccept);
            eventClosed += new EventDelegate.Closed(OnClientClosed);

        }

        private void OnClientClosed(IChannelHandlerContext context)
        {
            _logger.Debug($"{context.Channel.RemoteAddress} is closed\n");
            IEnumerable<ContextParas> listContextParas = listContext.TakeWhile(c => c.context == context);
            foreach (var c in listContextParas)
            {
                c.context.CloseAsync();
            }
        }

        private void OnClientAccept(IChannelHandlerContext context)
        {
            _logger.Debug($"{context.Channel.RemoteAddress} is connected\n");
            string strinit = "{\"type\":\"init\",\"msg\":{\"client_id\":\"7f0000010fa00000004d\"}}";
            listContext.AddFirst(new ContextParas(context));
            SendMessageAsync(strinit, context).Wait();
        }

        private void OnEventRecv(IChannelHandlerContext context, string ev)
        {
            _logger.Debug($"{context.Channel.RemoteAddress} recv event = {ev}\n");
       }


        private void OnMsgSend(IChannelHandlerContext context, string msg)
        {
            _logger.Debug($"{context.Channel.RemoteAddress} send msg\n{msg}\n");
        }

        private void OnMsgRecv(IChannelHandlerContext context, string msg)
        {
            _logger.Debug($"{context.Channel.RemoteAddress} recv msg\n{msg}\n");
            FxpPack fxpPack = JsonConvert.DeserializeObject<FxpPack>(msg);
            if (fxpPack != null)
            {
                switch (fxpPack.type)
                {
                    case "answer":
                        var commandReplyAsyncEvent = CommandAsyncEvents.Dequeue();
                        commandReplyAsyncEvent.Complete(msg);
                        break;
                    default: break;
                }
            }
        }

        public async Task<string> SendCommandAsync(string command)
        {
            IChannelHandlerContext context = listContext.First()?.context;
            if (context == null)
                _logger.Trace("has not active channel, send nothing");

            var asyncEvent = new FxpCommandAsyncEvent(command);
            CommandAsyncEvents.Enqueue(asyncEvent);
            _logger.Trace("{0} send command \n{1}\n", context.Channel.RemoteAddress, command);
            context.WriteAndFlushAsync(new TextWebSocketFrame(command));
            //if (_logger.IsTraceEnabled)
            //    _logger.Trace("Send to Server {0}:\n{1}\n", context.RemoteAddress, command.Command);
            //return await asyncEvent.Task as CommandReply;
            var reply = await asyncEvent.Task as string;
            return reply;
        }

        public async Task SendMessageAsync(string command, IChannelHandlerContext context)
        {
            //var asyncEvent = new FxpCommandAsyncEvent(command);
            //CommandAsyncEvents.Enqueue(asyncEvent);
            _logger.Trace("{0} send message:\n{1}\n", context.Channel.RemoteAddress, command);
            await context.WriteAndFlushAsync(new TextWebSocketFrame(command));
            //if (_logger.IsTraceEnabled)
            //    _logger.Trace("Send to Server {0}:\n{1}\n", context.RemoteAddress, command.Command);
            //return await asyncEvent.Task as CommandReply;
        }


    }
}
